<?php

namespace App\Http\Controllers\Machine;

use Carbon\Carbon;
use App\Exceptions\BusinessException;
use App\Http\Controllers\Controller;
use App\Import\RefundSignImport;
use App\Models\Refund\RefundSignDetailModel;
use App\Models\Refund\RefundSignModel;
use App\Models\Refund\RefundSignTotalModel;
use App\Models\SupplyModel;
use App\Utils\ApiResponse;
use App\Utils\ControllerModelTrait;
use App\Utils\ResponseEnum;
use App\Utils\VerifyRequestInput;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class RefundSignController extends Controller
{
    use ApiResponse, VerifyRequestInput, ControllerModelTrait;

    protected array $refundSignTotalDataKeys = [];
    protected array $refundSignTotalDataValues = [];

    /**
     * 获取商家列表
     * @param Request $request
     * @return JsonResponse
     */
    public function getList(Request $request): JsonResponse
    {
        $Model = RefundSignModel::getModel($request);
        $supplyCollection = self::getSupplyDataCache();
        $this->getRefundSignTotalData();
//        $offset = $request->input('pageSize') * ($request->input('page') - 1);
//        if ($offset < count($this->refundSignTotalDataKeys))
//            $Model = $Model->whereIn('sid', array_slice($this->refundSignTotalDataKeys, $offset, $request->input('pageSize')));
        $paginate = $Model->selectRaw('sid, SUM(goods_num) as num, SUM(goods_num * price) as total')->groupBy('sid')
            ->paginate($request->input('pageSize'));
        $items = $paginate->items();
        $list = $this->getRefundSignDataList($items, $supplyCollection);
        return $this->success([
            'total' => $paginate->total() ?: count($list),
            'page'  => $paginate->currentPage() ?: count($list),
            'pages' => $paginate->lastPage(),
            'list'  => $list,
//            'keys'  => $this->refundSignTotalDataKeys,
//            'values'=> $this->refundSignTotalDataValues
        ]);
    }

    /**
     * 获取商品列表
     * @param Request $request
     * @return JsonResponse
     */
    public function getGoodsList(Request $request): JsonResponse
    {
        $supplyCollection = self::getSupplyDataCache();
        $paginate = RefundSignModel::getModel($request)->paginate($request->input('pageSize'));
        $items = $paginate->items();
        $list = [];
        foreach ($items  as $item) {
            $supply = $supplyCollection->where('ID', $item->sid)->first();
            $item->sname = $supply ? $supply->CName : '';
            $list[] = $item;
        }
        return $this->success([
            'total' => $paginate->total(),
            'page'  => $paginate->currentPage(),
            'pages' => $paginate->lastPage(),
            'list'  => $list
        ]);
    }

    /**
     * 获取详情
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function getSupplyRefundInfo(Request $request): JsonResponse
    {
        $sid = $this->verifyId('sid');
        $pageSize = $request->input('pageSize', 10);
        $offset = $pageSize * ($request->input('page', 1) - 1);
        $goodsIds = RefundSignModel::where('goods_num', '>', 0)->where('sid', $sid)->distinct('goods_id')->select('goods_id')->offset($offset)->limit($pageSize)->pluck('goods_id');
        $refundSignCollection = RefundSignModel::where('sid', $sid)->whereIn('goods_id', $goodsIds)->get()->groupBy('goods_id');
        $data = [];
        foreach ($refundSignCollection as $goodsId => $list) {
            $listData = json_decode(json_encode($list), true);
            $data[] = [
                'goods_id'      => $goodsId,
                'goods_specs'   => $list,
                'goods_name'    => $listData[0]['goods_name'],
                'thumbnail'     => $listData[0]['thumbnail'],
                'cover'         => $listData[0]['thumbnail']
            ];
        }
        return $this->success($data);
    }

    /**
     * 保存数据
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function doSave(Request $request): JsonResponse
    {
        $orderNo = $request->input('order_no') ?: date('YmdHi');
        $direction = $this->verifyString('direction');
        $goodsList = json_decode($this->verifyString('goods_list'), true);
        if (!$request->input('forced') && $this->checkSignInOrOutValid($orderNo, $goodsList, $direction) === false)
            return $this->fail(ResponseEnum::REFUND_SIGN_INVALID);
        $this->doSaveDetail($orderNo, $goodsList, $direction);
        file_get_contents('https://www.toysmodel.cn/api/refund/sign/sync');
        return $this->success();
    }

    /**
     * 获取商家预退货现金总额
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function getSupplyAdvanceRefundTotal(Request $request): JsonResponse
    {
        $sid = $this->verifyId('sid');
        $total = RefundSignTotalModel::where('sid', $sid)->sum('total');
        return $this->success(['total' => $total ?: 0]);
    }

    /**
     * 预退抵扣
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function doMinusAdvanceRefundTotal(Request $request): JsonResponse
    {
        $sid = $this->verifyId('sid');
        $total = $this->verifyNumeric('total');
        $refundTotal = RefundSignTotalModel::where('sid', $sid)->sum('total');
        if ($refundTotal < $total || intval($total) <= 0)
            return $this->fail(ResponseEnum::REFUND_TOTAL_NOT_ENOUGH);
        RefundSignTotalModel::create([
            'sid'       => $sid,
            'total'     => -$total,
            'date'      => Carbon::today()->toDateString(),
            'doned_uid' => $request->input('uid'),
        ]);
        return $this->success(['total' => floatval($refundTotal - $total)]);
    }

    /**
     * 同步数据
     * @return JsonResponse
     */
    public function doSync(): JsonResponse
    {
        $collection = RefundSignDetailModel::where('sync_status', 0)->limit(5)->get();
        if ($collection) {
            $ids = [];
            foreach ($collection as $item) {
                $this->doSyncWithPrimaryTable($item);
                $ids[] = $item->id;
            }
            RefundSignDetailModel::whereIn('id', $ids)->update(['sync_status' => 1]);
        }
        return $this->success($collection);
    }

    /**
     *
     * 导入退款登记
     * @param Request $request
     * @return JsonResponse
     */
    public function doImport(Request $request): JsonResponse
    {
        $file = $request->file('file');
        if ($file && $file->isValid())
            \Maatwebsite\Excel\Facades\Excel::import(new RefundSignImport(), $file);
        return $this->success();
    }

    /**
     * 保存退款单/抵扣单明细
     * @param $orderNo
     * @param $goodsList
     * @param $direction:direction:in(退款进账)，total正值；direction:out抵扣(置换出账)，total负值
     * @return void
     */
    private function doSaveDetail($orderNo, $goodsList, $direction): void
    {
        $array = [];
        foreach ($goodsList as $goods) {
            $total = floatval($goods['price'] * $goods['goods_num']);
            # 合计各店铺退货金额
            if ($direction == 'out') {
                if (isset($array[$goods['sid']]))
                    $array[$goods['sid']] += $total;
                else
                    $array[$goods['sid']] = $total;
            }
            RefundSignDetailModel::create([
                'sid'           => $goods['sid'],
                'order_no'      => $orderNo,
                'goods_id'      => $goods['goods_id'],
                'goods_name'    => $goods['goods_name'],
                'goods_sn'      => $goods['goods_sn'],
                'thumbnail'     => $goods['thumbnail'],
                'color'         => $goods['color'],
                'size'          => $goods['size'],
                'weight'        => $goods['weight'],
                'price'         => $goods['price'],
                'goods_num'     => $goods['goods_num'],
                'total'         => $direction == 'in' ? $total : 0 - $total,
                'doned_uid'     => request()->input('uid')
            ]);
        }
        # 提前退货，记录退款金额
        if (\request()->input('advance'))
            $this->doSaveRefundSignTotal($array, request()->input('uid'));
    }

    /**
     * 提前退货，记录退款金额
     * @param $data
     * @param $uid
     * @return void
     */
    private function doSaveRefundSignTotal($data, $uid): void
    {
        $date = Carbon::today()->toDateString();
        foreach ($data as $sid => $total) {
            if ($total) {
                RefundSignTotalModel::create([
                    'sid'       => $sid,
                    'total'     => $total,
                    'date'      => $date,
                    'doned_uid' => $uid,
                ]);
            }
        }
    }

    /**
     * 同步退款单/抵扣单数据到主表
     * @param $item
     * @return void
     */
    private function doSyncWithPrimaryTable($item): void
    {
        $goodsItem = RefundSignModel::where('goods_id', $item->goods_id)->where('goods_sn', $item->goods_sn)->first();
        if ($goodsItem) {
            $goodsItem->goods_num = $item->total > 0 ? $goodsItem->goods_num + $item->goods_num : $goodsItem->goods_num - $item->goods_num;
            $goodsItem->goods_num = max(0, $goodsItem->goods_num);
            $goodsItem->save();
        } else {
            RefundSignModel::create([
                'sid'           => $item->sid,
                'goods_id'      => $item->goods_id,
                'goods_name'    => $item->goods_name,
                'goods_sn'      => $item->goods_sn,
                'thumbnail'     => $item->thumbnail,
                'color'         => $item->color,
                'size'          => $item->size,
                'weight'        => $item->weight,
                'price'         => $item->price,
                'goods_num'     => $item->goods_num,
                'doned_uid'     => $item->doned_uid
            ]);
        }
    }

    /**
     * 校验登记是否合法
     * @param $orderNo
     * @param $goodsList
     * @param $direction
     * @return true
     */
    private function checkSignInOrOutValid($orderNo, $goodsList, $direction): bool
    {
        if ($direction == 'in') {
            $goodsSns = array_column($goodsList, 'goods_sn');
            if (RefundSignDetailModel::where('order_no', $orderNo)->whereIn('goods_sn', $goodsSns)->select(['goods_sn'])->first())
                return false;
        } else {
            $outTotal = 0;
            $sids = [];
            foreach ($goodsList as $item) {
                if ($item) {
                    $outTotal += $item['price'] * $item['goods_num'];
                    $sids[] = $item['sid'];
                }
            }
            $row = RefundSignModel::where('sid', $sids[0])->selectRaw('SUM(goods_num * price) as total')->first();
            if (count(array_filter($sids)) > 1 || $outTotal > ($row ? $row->total : 0))
                return false;
        }
        return true;
    }

    /**
     * 获取默认搜索商家统计数据
     * @param $items
     * @param $supplyCollection
     * @return array
     */
    private function getRefundSignDataList($items, $supplyCollection): array
    {
        $list = [];
        if (count($items) <= 0 && $supplyCollection->isNotEmpty()) {
            $supply = array_values($supplyCollection->toArray())[0];
            $money = RefundSignTotalModel::where('sid', $supply['ID'])->sum('total');
            $list[] = ['sid' => $supply['ID'], 'sname' => $supply['CName'], 'num' => 0, 'total' => 0, 'money' => $money ?: 0];
        } else {
           foreach ($items  as $item) {
                $supply = $supplyCollection->where('ID', $item->sid)->first();
                $item->sname = $supply ? $supply->CName : '';
                $index = array_search($item->sid, $this->refundSignTotalDataKeys);
                $item->money = $index === false ? 0 : $this->refundSignTotalDataValues[$index];
                $list[] = $item;
            };
        }
        return $list;
    }

    /**
     * 汇总退货登记商家统计
     * @return void
     */
    private function getRefundSignTotalData(): void
    {
        $sql = 'SELECT sid, SUM(total) AS money FROM refund_sign_total  GROUP BY sid HAVING sum(total) > 0  ORDER BY money DESC';
        $collection = DB::select($sql);
        $data = json_decode(json_encode($collection), true);
        $this->refundSignTotalDataKeys = array_column($data, 'sid');
        $this->refundSignTotalDataValues = array_column($data, 'money');
    }

    /**
     * 获取厂家列表缓存
     * @return mixed
     */
    public static function getSupplyDataCache(): mixed
    {
        if (!Cache::has('MachineSupplyList'))
            Cache::put('MachineSupplyList', SupplyModel::all(['ID', 'CName', 'room']), 24 * 3600);
        $collection = Cache::get('MachineSupplyList');
        if (\request()->input('keyword')) {
            $keyword = \request()->input('keyword');
            $collection = $collection->filter(function ($item) use ($keyword) {
                return str_contains($item->CName, $keyword) || $item->room == $keyword;
            });
        }
        return $collection;
    }
}
